import datetime

from geopy.distance import great_circle
from rest_framework import serializers

import settings
from social.account.models import User
from social.enums import is_in_review
from social.exceptions import CodeException
from social.gift.serializers import GiftSerializer
from social.user.models import AVCallSetting, UserLike, UserBlock, UserMsgSetting, UserVisit, UserLevel, UserChatUp, \
    UserCallData, GiftWall
from social.utils import json_utils
from social.utils.serializers import HashidField, CityNameField
from social.utils.shortcut import get_object_or_none


class SimpleUserSerializer(serializers.ModelSerializer):
    id = HashidField(model=User)
    nickname = serializers.SerializerMethodField()
    avatar = serializers.ImageField()
    photos = serializers.SerializerMethodField()
    birthday = serializers.DateField(format='%Y-%m-%d')
    role = serializers.SerializerMethodField()

    def get_nickname(self, instance):
        return instance.nickname if instance.nickname else f'用户{instance.uid}'

    def get_photos(self, instance):
        if instance.photos:
            arr = json_utils.to_json(instance.photos)
            return list(map(lambda x: settings.IMAGE_HOST + x, arr))
        return []

    def get_role(self, instance):
        request = self.context.get('request')
        if is_in_review(request):
            return ''
        return instance.role

    def _get_distance(self, instance):
        if instance.hide_location:
            return ''
        request = self.context.get('request')
        if request and request.user:
            user = request.user
            if user.lat and user.lng and instance.lat and instance.lng:
                km = great_circle((user.lat, user.lng), (instance.lat, instance.lng)).kilometers
                return '距离{:.2f}km'.format(max(0.01, km))
            else:
                return ''
        else:
            return ''

    def _get_last_active(self, instance):
        print(instance.last_active)
        if instance.hide_last_active:
            return ''
        mins = int((datetime.datetime.now().timestamp() - instance.last_active.timestamp()) / 60)
        if mins <= 5:
            return '在线'
        elif mins < 60:
            return f'{mins}分钟前'
        elif mins < 24 * 60:
            return f'{int(mins / 60)}小时前'
        elif mins < 24 * 60 * 30:
            return f'{int(mins / 1440)}天前'
        else:
            return '1个月前'

    class Meta:
        model = User
        fields = (
            'id', 'nickname', 'gender', 'uid', 'im_id', 'avatar', 'bio', 'relationship', 'height', 'weight', 'birthday',
            'photos', 'role', 'avatar_auth', 'is_vip', 'vip_expired_time')


class HomeUserSerializer(SimpleUserSerializer):
    distance = serializers.SerializerMethodField()
    last_active = serializers.SerializerMethodField()

    def _fetch_chat_up_users(self):
        chat_up_ids = self.context.get('chat_up_ids')
        if chat_up_ids:
            return chat_up_ids
        request = self.context.get('request')
        if request and request.user:
            like_ids = UserChatUp.objects.values_list('to_user_id', flat=True).filter(from_user=request.user)
            self.context.update({'chat_up_ids': like_ids})
            return like_ids

    def get_distance(self, instance):
        return self._get_distance(instance)

    def get_last_active(self, instance):
        return self._get_last_active(instance)

    def to_representation(self, instance):
        data = super(HomeUserSerializer, self).to_representation(instance)
        now = datetime.datetime.now().timestamp()
        if instance.last_active and (now - instance.last_active.timestamp() < 300):
            data['is_online'] = True
        else:
            data['is_online'] = False
        request = self.context.get('request')
        if request and request.user.gender == 'g':
            data['chat_up'] = True
        else:
            data['chat_up'] = instance.id in self._fetch_chat_up_users()
        return data

    class Meta:
        model = User
        fields = (
            'id', 'nickname', 'gender', 'uid', 'im_id', 'avatar', 'bio', 'relationship', 'height', 'weight', 'birthday',
            'photos', 'role', 'avatar_auth', 'is_vip', 'vip_expired_time', 'distance', 'last_active')


class UserSerializer(SimpleUserSerializer):
    city_name = CityNameField(source='city')
    desc = serializers.SerializerMethodField()

    def get_desc(self, instance):
        desc_list = []
        distance = self._get_distance(instance)
        if distance:
            desc_list.append(distance)
        last_active = self._get_last_active(instance)
        if last_active:
            desc_list.append(last_active)
        desc_list.append(f'{instance.be_like_count}获赞')
        desc_list.append(f'{instance.fans_count}粉丝')
        return '·'.join(desc_list)

    def to_representation(self, instance):
        data = super(UserSerializer, self).to_representation(instance)
        request = self.context.get('request')
        if instance.gender == 'g' and instance.avatar_auth:
            av_call_setting, _ = AVCallSetting.objects.get_or_create(user=instance)
            video_call_price, audio_video_price = av_call_setting.call_price
            data['av_call_setting'] = {
                'call_enabled': av_call_setting.call_enabled,
                'video_call_price': video_call_price,
                'audio_call_price': audio_video_price
            }
        if request and request.user and request.user.id == instance.id:
            data['in_review'] = is_in_review(request)
        if request and request.user and request.user.id != instance.id:
            data['is_follow'] = UserLike.is_follow(request.user, instance)
            data['is_block'] = UserBlock.is_block(request.user, instance)
            if request.user.gender == 'g':
                data['chat_up'] = True
            else:
                data['chat_up'] = UserChatUp.is_chat_up(request.user, instance)
        if request and request.user:
            user_level = get_object_or_none(UserLevel, user=instance)
            data['wealth_level'] = user_level.wealth_level if user_level else 0
            data['charm_level'] = user_level.charm_level if user_level else 0
        return data

    class Meta:
        model = User
        fields = (
            'id', 'nickname', 'gender', 'uid', 'im_id', 'avatar', 'bio', 'relationship', 'height', 'weight', 'birthday',
            'photos', 'follow_count', 'fans_count', 'friend_count', 'job', 'city_name', 'desc', 'role',
            'avatar_auth', 'is_vip', 'vip_expired_time', 'hide_location', 'hide_last_active')


class FollowerSerializer(serializers.ModelSerializer):
    def to_representation(self, instance):
        data = SimpleUserSerializer(instance.to_user).data
        data['is_follow'] = True
        return data

    class Meta:
        model = UserLike
        fields = ('to_user',)


class BlockSerializer(serializers.ModelSerializer):
    def to_representation(self, instance):
        data = SimpleUserSerializer(instance.to_user).data
        return data

    class Meta:
        model = UserLike
        fields = ('to_user',)


class FansSerializer(serializers.ModelSerializer):

    def _fetch_user_fans(self):
        follow_ids = self.context.get('fans_ids')
        if follow_ids:
            return follow_ids
        request = self.context.get('request')
        if request and request.user:
            like_ids = UserLike.objects.values_list('to_user_id', flat=True).filter(from_user=request.user)
            self.context.update({'follow_ids': like_ids})
            return like_ids

    def to_representation(self, instance):
        data = SimpleUserSerializer(instance.from_user).data
        follow_ids = self._fetch_user_fans()
        data['is_follow'] = follow_ids and instance.from_user_id in follow_ids
        return data

    class Meta:
        model = UserLike
        fields = ('from_user',)


class VisitorSerializer(serializers.ModelSerializer):
    user = SimpleUserSerializer(source='from_user')

    class Meta:
        model = UserVisit
        fields = ('times', 'user', 'updated_at')


class AVCallUserSerializer(SimpleUserSerializer):

    def to_representation(self, instance):
        data = super(AVCallUserSerializer, self).to_representation(instance)
        try:
            av_call_setting = instance.av_call_setting
            if av_call_setting:
                video_call_price, audio_video_price = av_call_setting.call_price
                data['av_call_setting'] = {
                    'call_enabled': av_call_setting.call_enabled,
                    'video_call_price': video_call_price,
                    'audio_call_price': audio_video_price
                }
        except Exception:
            pass
        now = datetime.datetime.now().timestamp()
        if instance.last_active and (now - instance.last_active.timestamp() < 300):
            data['is_online'] = True
        else:
            data['is_online'] = False
        return data


class AVCallSettingSerializer(serializers.ModelSerializer):
    call_enabled = serializers.BooleanField(required=False)
    setting_level = serializers.IntegerField(required=False)

    def validate_setting_level(self, setting_level):
        if setting_level > self.instance.this_week_level:
            raise CodeException(msg=f'当前视频等级不够')
        return setting_level

    def to_representation(self, instance):
        request = self.context.get('request')
        data = super(AVCallSettingSerializer, self).to_representation(instance)
        this_week = datetime.datetime.now()
        call_data, _ = UserCallData.objects.get_or_create(week=UserCallData.key_week(this_week), user=request.user)
        data['this_week_duration'] = call_data.call_duration
        last_week = this_week - datetime.timedelta(days=7)
        call_data, _ = UserCallData.objects.get_or_create(week=UserCallData.key_week(last_week), user=request.user)
        data['last_week_duration'] = call_data.call_duration
        return data

    class Meta:
        model = AVCallSetting
        fields = ('call_enabled', 'setting_level', 'this_week_level', 'last_week_level')


class UserMsgSettingSerializer(serializers.ModelSerializer):
    class Meta:
        model = UserMsgSetting
        fields = ('new_msg', 'msg_summary', 'post_comment', 'post_like', 'new_fans', 'new_visited', 'special')


class UserLevelSerializer(serializers.ModelSerializer):
    class Meta:
        model = UserLevel
        fields = ('wealth_value', 'wealth_level', 'charm_value', 'charm_level')


class GiftWallSerializer(serializers.ModelSerializer):
    gift = GiftSerializer()

    class Meta:
        model = GiftWall
        fields = ('gift', 'count')
